home *** CD-ROM | disk | FTP | other *** search
/ Aminet 51 / Aminet 51 (2002)(GTI - Schatztruhe)[!][Oct 2002].iso / Aminet / util / arc / xadmasterdev.lha / xad / Sources / tools / xad2lha.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-20  |  30.4 KB  |  1,353 lines

  1. #define NAME         "xad2lha"
  2. #define DISTRIBUTION "(Freeware) "
  3. #define REVISION     "3"
  4. #define DATE         "06.01.2002"
  5.  
  6. /* Programmheader
  7.  
  8.     Name:        xad2lha
  9.     Author:        SDI
  10.     Distribution:    Freeware
  11.     Description:    recompresses file archives in lha format
  12.     Compileropts:    -
  13.     Linkeropts:    -gsi -l amiga
  14.  
  15.  1.0   19.08.99 : first version
  16.  1.1   15.04.00 : added support for disk archives
  17.  1.2   05.01.02 : fixed buffer initialisation bug
  18.  1.3   06.01.02 : added support for disk images
  19. */
  20.  
  21. #include <proto/xadmaster.h>
  22. #include <proto/exec.h>
  23. #include <proto/dos.h>
  24. #include <exec/memory.h>
  25. #include <dos/dosasl.h>
  26. #include <utility/hooks.h>
  27. #include "SDI_version.h"
  28. #include "SDI_compiler.h"
  29. #define SDI_TO_ANSI
  30. #include "SDI_ASM_STD_protos.h"
  31.  
  32. struct xadMasterBase *     xadMasterBase = 0;
  33. struct DosLibrary *     DOSBase = 0;
  34. struct ExecBase *     SysBase  = 0;
  35.  
  36. #define MINPRINTSIZE    51200    /* 50KB */
  37.  
  38. #define PARAM    "FROM/A,TO,PASSWORD/K,NOEXTERN/S,QUIET/S,HEADER0/S"
  39.  
  40. #define OPTIONS \
  41.   "FROM       The input archive file (no patterns allowed)\n"        \
  42.   "TO         The destination archive file\n"                \
  43.   "PASSWORD   A password for encrypted archives\n"            \
  44.   "NOEXTERN   Turns off usage of external clients\n"            \
  45.   "QUIET      Turns off progress report\n"                \
  46.   "HEADER0    Produces header level 0 files\n"
  47.  
  48. struct Args {
  49.   STRPTR   from;
  50.   STRPTR   to;
  51.   STRPTR   password;
  52.   ULONG    noextern;
  53.   ULONG    quiet;
  54.   ULONG    header0;
  55. };
  56.  
  57. void MakeEntry0(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize);
  58. void MakeEntry2(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize);
  59. ULONG MakeLH(STRPTR mem, ULONG size, ULONG bits);
  60. void ProcessEntry(struct xadFileInfo *fi, struct xadArchiveInfo *ai, struct Args *args, BPTR outfh,
  61.   STRPTR tmp, LONG disk);
  62.  
  63. ULONG start(void)
  64. {
  65.   ULONG ret = RETURN_FAIL;
  66.   struct DosLibrary *dosbase;
  67.  
  68.   SysBase = (*((struct ExecBase **) 4));
  69.   { /* test for WB and reply startup-message */
  70.     struct Process *task;
  71.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  72.     {
  73.       WaitPort(&task->pr_MsgPort);
  74.       Forbid();
  75.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  76.       return RETURN_FAIL;
  77.     }
  78.   }
  79.  
  80.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  81.   {
  82.     LONG err = 0;
  83.     struct xadMasterBase *xadmasterbase;
  84.  
  85.     DOSBase = dosbase;
  86.     if((xadmasterbase = (struct xadMasterBase *)
  87.     OpenLibrary("xadmaster.library", 5)))
  88.     {
  89.       struct Args args;
  90.       struct RDArgs *rda;
  91.       
  92.       memset(&args, 0, sizeof(struct Args));
  93.       xadMasterBase = xadmasterbase;
  94.  
  95.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  96.       {
  97.         rda->RDA_ExtHelp = OPTIONS;
  98.  
  99.         if(ReadArgs(PARAM, (LONG *) &args, rda))
  100.         {
  101.           struct xadArchiveInfo *ai;
  102.           struct xadFileInfo *fi;
  103.           struct xadDiskInfo *di;
  104.           BPTR outfh;
  105.       STRPTR tmp;
  106.           ULONG i;
  107.  
  108.           if((tmp = (STRPTR) AllocMem(2048, MEMF_ANY)))
  109.           {
  110.             if(!args.to)
  111.             {
  112.               i = strlen(args.from);
  113.               CopyMem(args.from, tmp, i+1);
  114.  
  115.               do
  116.               {
  117.                 --i;
  118.                 if(tmp[i] == '.')
  119.                   tmp[i] = 0;
  120.               } while(i && tmp[i] != '/' && tmp[i] != ':'); 
  121.               CopyMem(".lha", tmp + strlen(tmp), 5);
  122.               args.to = tmp;
  123.             }
  124.     
  125.             if((ai = (struct xadArchiveInfo *) xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  126.             {
  127.           if(!(err = xadGetInfo(ai, XAD_INFILENAME, args.from, XAD_NOEXTERN, args.noextern,
  128.               args.password ? XAD_PASSWORD : TAG_IGNORE, args.password, TAG_DONE)))
  129.               {
  130.             if((ai->xai_Flags & XADAIF_FILECORRUPT) && !args.quiet)
  131.               Printf("!!! The archive file has some corrupt data. !!!\n");
  132.  
  133.             if((outfh = Open(args.to, MODE_NEWFILE)))
  134.             {
  135.           ret = 0;
  136.               fi = ai->xai_FileInfo;
  137.               di = ai->xai_DiskInfo;
  138.  
  139.           if(!args.quiet)
  140.             Printf("Original Crunched Ratio  OldCrun Name\n"
  141.             "------------------------------------------------------\n");
  142.  
  143.           while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  144.           {
  145.             ProcessEntry(fi, ai, &args, outfh, tmp, 0);
  146.               fi = fi->xfi_Next;
  147.               }
  148.           while(di && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  149.           {
  150.             struct xadArchiveInfo *aid;
  151.  
  152.                 if((aid = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  153.                 {
  154.                   struct TagItem ti[5];
  155.  
  156.                 ti[0].ti_Tag = XAD_INFILENAME;
  157.                 ti[0].ti_Data = (ULONG) args.from;
  158.                 ti[1].ti_Tag = XAD_ENTRYNUMBER;
  159.                 ti[1].ti_Data = di->xdi_EntryNumber;
  160.                 ti[2].ti_Tag = XAD_NOEXTERN;
  161.                 ti[2].ti_Data = args.noextern;
  162.                 ti[3].ti_Tag = args.password ? XAD_PASSWORD : TAG_IGNORE;
  163.                 ti[3].ti_Data = (ULONG) args.password;
  164.                 ti[4].ti_Tag = TAG_DONE;
  165.  
  166.               if(!args.quiet)
  167.                     Printf("Processing disk entry %ld.\n", di->xdi_EntryNumber);
  168.                 if(!(i = xadGetDiskInfo(aid, XAD_INDISKARCHIVE, ti, TAG_DONE)))
  169.                 {
  170.                     if((aid->xai_Flags & XADAIF_FILECORRUPT) && !args.quiet)
  171.                       Printf("!!! Disk has some corrupt data. !!!\n");
  172.                     fi = aid->xai_FileInfo;
  173.                     while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  174.                     {
  175.                   ProcessEntry(fi, aid, &args, outfh, tmp, 1);
  176.                   fi = fi->xfi_Next;
  177.                 }
  178.                 xadFreeInfo(aid);
  179.               }
  180.               else if(!args.quiet)
  181.                  Printf("Failed to extract data form disk archive: %s\n", xadGetErrorText(i));
  182.               xadFreeObjectA(aid, 0);
  183.             }
  184.             di = di->xdi_Next;
  185.               }
  186.               NameFromFH(outfh, tmp, 2048);
  187.               Close(outfh);
  188.               SetProtection(tmp, FIBF_EXECUTE);
  189.             }
  190.                 xadFreeInfo(ai);
  191.           } /* xadGetInfo */
  192.           else
  193.           {
  194.                 struct xadArchiveInfo *aii;
  195.  
  196.                 if((aii = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  197.                 {
  198.                   if(!args.quiet)
  199.                     Printf("Trying file as image file.\n");
  200.                   if(!(i = xadGetDiskInfo(aii, XAD_INFILENAME, args.from, XAD_NOEXTERN,
  201.                   args.noextern, args.password ? XAD_PASSWORD : TAG_IGNORE, args.password,
  202.                   TAG_DONE)))
  203.                   {
  204.                     err = 0;
  205.                     if((aii->xai_Flags & XADAIF_FILECORRUPT) && !args.quiet)
  206.                       Printf("!!! Image has some corrupt data. !!!\n");
  207.  
  208.                     if((outfh = Open(args.to, MODE_NEWFILE)))
  209.                     {
  210.                       ret = 0;
  211.  
  212.                       if(!args.quiet)
  213.                         Printf("Original Crunched Ratio  OldCrun Name\n"
  214.                         "------------------------------------------------------\n");
  215.  
  216.                       fi = aii->xai_FileInfo;
  217.                       while(fi && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  218.                       {
  219.                         ProcessEntry(fi, aii, &args, outfh, tmp, 1);
  220.                         fi = fi->xfi_Next;
  221.                       }
  222.                       NameFromFH(outfh, tmp, 2048);
  223.                       Close(outfh);
  224.                       SetProtection(tmp, FIBF_EXECUTE);
  225.                     } /* Open */
  226.                     xadFreeInfo(aii);
  227.                   } /* xadGetDiskInfo */
  228.                   xadFreeObjectA(aii, 0);
  229.                 } /* xadAllocObject */
  230.               } /* else xadGetInfo */
  231.               xadFreeObjectA(ai, 0);
  232.             } /* xadAllocObject */
  233.             FreeMem(tmp, 2048);
  234.           } /* AllocMem(tmp); */
  235.           FreeArgs(rda);
  236.         } /* ReadArgs */
  237.         FreeDosObject(DOS_RDARGS, rda);
  238.       } /* AllocDosObject */
  239.  
  240.       if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  241.         SetIoErr(ERROR_BREAK);
  242.  
  243.       if(!args.quiet)
  244.       {
  245.         if(err)
  246.       Printf("An error occured: %s\n", xadGetErrorText(err));
  247.         else if(ret)
  248.           PrintFault(IoErr(), 0);
  249.       }
  250.  
  251.       CloseLibrary((struct Library *) xadmasterbase);
  252.     } /* OpenLibrary xadmaster */
  253.     else
  254.       Printf("Could not open xadmaster.library\n");
  255.     CloseLibrary((struct Library *) dosbase);
  256.   } /* OpenLibrary dos */
  257.   return ret;
  258. }
  259.  
  260. void ProcessEntry(struct xadFileInfo *fi, struct xadArchiveInfo *ai, struct Args *args, BPTR outfh,
  261. STRPTR tmp, LONG disk)
  262. {
  263.   ULONG i, res = 0;
  264.  
  265.   if(fi->xfi_Flags & XADFIF_LINK)
  266.   {
  267.     if(!args->quiet)
  268.       Printf("Skipped Link\n");
  269.   }
  270.   else if(fi->xfi_Flags & XADFIF_DIRECTORY)
  271.   {
  272.     if(args->header0)
  273.       MakeEntry0(fi, tmp, outfh, 0, 0, &i);
  274.     else
  275.       MakeEntry2(fi, tmp, outfh, 0, 0, &i);
  276.     if(!args->quiet)
  277.       Printf("   <dir>    <dir>                %s\n", fi->xfi_FileName);
  278.   }
  279.   else if(fi->xfi_Flags & XADFIF_NOUNCRUNCHSIZE)
  280.   {
  281.     Printf("Skipping entry of unknown size: %s\n", fi->xfi_FileName);
  282.   }
  283.   else if(!fi->xfi_Size)
  284.   {
  285.     if(args->header0)
  286.       MakeEntry0(fi, tmp, outfh, 0, 0, &res);
  287.     else
  288.       MakeEntry2(fi, tmp, outfh, 0, 0, &res);
  289.     Printf("       0        0  0.0%%        0 %s\n", fi->xfi_FileName);
  290.   }
  291.   else
  292.   {
  293.     STRPTR outmem;
  294.  
  295.     if((outmem = (STRPTR) AllocMem(fi->xfi_Size, MEMF_ANY)))
  296.     {
  297.       if(disk)
  298.         i = xadDiskFileUnArc(ai, XAD_OUTMEMORY, outmem, XAD_ENTRYNUMBER,
  299.         fi->xfi_EntryNumber, XAD_OUTSIZE, fi->xfi_Size, TAG_DONE);
  300.       else
  301.         i = xadFileUnArc(ai, XAD_OUTMEMORY, outmem, XAD_ENTRYNUMBER,
  302.         fi->xfi_EntryNumber, XAD_OUTSIZE, fi->xfi_Size, TAG_DONE);
  303.       if(!i)
  304.       {
  305.         if(args->header0)
  306.           MakeEntry0(fi, tmp, outfh, outmem, fi->xfi_Size, &res);
  307.         else
  308.           MakeEntry2(fi, tmp, outfh, outmem, fi->xfi_Size, &res);
  309.         if(!args->quiet)
  310.     {
  311.       ULONG i = 0, j = 0;
  312.  
  313.       if(res < fi->xfi_Size)
  314.       {
  315.         i = ((fi->xfi_Size - res)*1000)/fi->xfi_Size;
  316.         j = i % 10;
  317.             i /= 10;
  318.           }
  319.           if(fi->xfi_Flags & XADFIF_GROUPED)
  320.             Printf("%8ld %8ld %2ld.%1ld%%   merged %s\n", fi->xfi_Size, res, i, j, fi->xfi_FileName);
  321.           else
  322.             Printf("%8ld %8ld %2ld.%1ld%% %8ld %s\n", fi->xfi_Size, res, i, j, fi->xfi_CrunchSize, fi->xfi_FileName);
  323.         }
  324.       }
  325.       else if(!args->quiet)
  326.         Printf("Failed to extract file %s: %s\n", fi->xfi_FileName, xadGetErrorText(i));
  327.     }
  328.     FreeMem(outmem, fi->xfi_Size);
  329.   }
  330. }
  331.  
  332. void Store32(STRPTR s, ULONG v)
  333. {
  334.   ULONG i;
  335.  
  336.   for(i = 0; i < 4; ++i)
  337.   {
  338.     *(s++) = v;
  339.     v >>= 8;
  340.   }
  341. }
  342.  
  343. void Store16(STRPTR s, ULONG v)
  344. {
  345.   *(s++) = v;
  346.   *s = v >> 8;
  347. }
  348.  
  349. /* Header structure!
  350.   UBYTE    HeaderSize              0  *
  351.   UBYTE    CheckSum             1  *
  352.   UBYTE*5  HeaderID             2  *
  353.   ULONG    CompSize             7  *
  354.   ULONG    Size                11  *
  355.   ULONG       Time                15  *
  356.   UBYTE    Attribute            19  *
  357.   UBYTE       Level (0)            20  *
  358.   UBYTE       NameSize            21  *
  359.   file name
  360.   UWORD       CRC                22+s
  361.   data
  362. */
  363.  
  364. void MakeEntry0(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize)
  365. {
  366.   ULONG ns, cs, hs, j;
  367.  
  368.   tmp[2] = tmp[6] = '-';
  369.   tmp[3] = 'l';
  370.   tmp[4] = 'h';
  371.   tmp[5] = '0';
  372.   Store32(tmp+7, size);
  373.   Store32(tmp+11, size);
  374.   tmp[19] = fi->xfi_Protection;
  375.   tmp[20] = 0;
  376.  
  377.   xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date, XAD_GETDATEMSDOS, &ns, TAG_DONE);
  378.   Store32(tmp+15, ns);
  379.  
  380.   ns = strlen(fi->xfi_FileName) + (fi->xfi_Flags & XADFIF_DIRECTORY ? 1 : 0);
  381.   cs = strlen(fi->xfi_Comment);
  382.   hs = ns + cs + (cs ? 1 : 0);
  383.   tmp[21] = hs;
  384.  
  385.   hs += 22;
  386.   Store16(tmp+hs, size ? xadCalcCRC16(XADCRC16_ID1, 0, size, mem) : 0);
  387.  
  388.   for(j = 0; j < ns; ++j)
  389.     tmp[22 + j] = fi->xfi_FileName[j] == '/' ? '\\' : fi->xfi_FileName[j];
  390.   if(cs)
  391.   {
  392.     tmp[22+ns] = 0;
  393.     CopyMem(fi->xfi_Comment, tmp+22+ns+1, cs);
  394.   }
  395.   if(fi->xfi_Flags & XADFIF_DIRECTORY)
  396.     tmp[22+ns-1] = '/';
  397.   else
  398.   {
  399.     /* Compressable ? */
  400.     if(size && (ns = MakeLH(mem, size, 13)))
  401.     {
  402.       tmp[5] = '5';
  403.       size = ns;
  404.       Store32(tmp+7, size);
  405.     }
  406.   }
  407.  
  408.   *ressize = size;
  409.   for(cs = ns = 0; cs < hs; ++cs)
  410.     ns += tmp[2+cs];
  411.   tmp[1] = ns;
  412.   tmp[0] = hs;
  413.   Write(fh, tmp, hs+2);
  414.   if(size)
  415.     Write(fh, mem, size);
  416. }
  417.  
  418. #define TM_UREAD      00400 /* Read by owner */
  419. #define TM_UWRITE     00200 /* Write by owner */
  420. #define TM_UEXEC      00100 /* Execute/search by owner */
  421. #define TM_GREAD      00040 /* Read by group */
  422. #define TM_GWRITE     00020 /* Write by group */
  423. #define TM_GEXEC      00010 /* Execute/search by group */
  424. #define TM_OREAD      00004 /* Read by other */
  425. #define TM_OWRITE     00002 /* Write by other */
  426. #define TM_OEXEC     00001 /* Execute/search by other */
  427.  
  428. /* Header structure!
  429.   UWORD       TotalHeaderSize         0  *
  430.   UBYTE*5  HeaderID             2  *
  431.   ULONG    CompSize             7  *
  432.   ULONG    Size                11  *
  433.   ULONG       Time                15  *
  434.   UBYTE    Attribute            19  *
  435.   UBYTE       Level (2)            20  *
  436.   UWORD    CRC                    21  *
  437.   UBYTE    SystemID ('A')        23  *
  438.   UWORD    FirstExtHeaderSize        24
  439.   extended headers
  440.   data
  441. */
  442. void MakeEntry2(struct xadFileInfo *fi, STRPTR tmp, BPTR fh, STRPTR mem, ULONG size, ULONG *ressize)
  443. {
  444.   ULONG headersize = 26, i, j, k;
  445.  
  446.   tmp[2] = tmp[6] = '-';
  447.   tmp[3] = 'l';
  448.   tmp[4] = 'h';
  449.   Store32(tmp+7, size);
  450.   Store32(tmp+11, size);
  451.   tmp[19] = fi->xfi_Protection;
  452.   tmp[20] = 2;
  453.   Store16(tmp+21, size ? xadCalcCRC16(XADCRC16_ID1, 0, size, mem) : 0);
  454.   tmp[23] = 'A';
  455.  
  456.   xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date, XAD_GETDATEMSDOS, &k, TAG_DONE);
  457.   Store32(tmp+15, k);
  458.  
  459.   if(fi->xfi_Flags & XADFIF_DIRECTORY)
  460.   {
  461.     tmp[5] = 'd';
  462.     i = strlen(fi->xfi_FileName);
  463.     Store16(tmp + headersize-2, i+3); /* set header size */
  464.     tmp[headersize++] = 0x02;
  465.     for(j = 0; j < i; ++j)
  466.       tmp[headersize++] = fi->xfi_FileName[j] == '/' ? 0xFF : fi->xfi_FileName[j];
  467.     headersize += 2;
  468.   }
  469.   else
  470.   {
  471.     STRPTR m;
  472.  
  473.     tmp[5] = '0';
  474.     m = FilePart(fi->xfi_FileName);
  475.  
  476.     i = strlen(m);
  477.     Store16(tmp + headersize-2, i+3); /* set header size */
  478.     tmp[headersize] = 0x01;
  479.     CopyMem(m, tmp+headersize+1, i);
  480.     headersize += i+3;
  481.     if(m != fi->xfi_FileName)
  482.     {
  483.       i = m-fi->xfi_FileName-1;
  484.       Store16(tmp + headersize-2, i+3); /* set header size */
  485.       tmp[headersize++] = 0x02;
  486.       for(j = 0; j < i; ++j)
  487.         tmp[headersize++] = fi->xfi_FileName[j] == '/' ? 0xFF : fi->xfi_FileName[j];
  488.       headersize += 2;
  489.     }
  490.  
  491.     /* Compressable ? */
  492.     if(size && (i = MakeLH(mem, size, 13)))
  493.     {
  494.       tmp[5] = '5';
  495.       size = i;
  496.       Store32(tmp+7, size);
  497.     }
  498.   }
  499.  
  500.   *ressize = size;
  501.  
  502.   if(fi->xfi_Protection & 0xFFFFFF00)
  503.   {
  504.     /* store UNIX protection */
  505.     Store16(tmp + headersize-2, 5); /* set header size */
  506.     i = fi->xfi_Protection;
  507.     j = 0;
  508.  
  509.     if(!(i & FIBF_READ))    j |= TM_UREAD;
  510.     if(!(i & FIBF_WRITE))     j |= TM_UWRITE;
  511.     if(!(i & FIBF_EXECUTE))    j |= TM_UEXEC;
  512.     if(i & FIBF_GRP_READ)     j |= TM_GREAD;
  513.     if(i & FIBF_GRP_WRITE)    j |= TM_GWRITE;
  514.     if(i & FIBF_GRP_EXECUTE)    j |= TM_GEXEC;
  515.     if(i & FIBF_OTR_READ)     j |= TM_OREAD;
  516.     if(i & FIBF_OTR_WRITE)    j |= TM_OWRITE;
  517.     if(i & FIBF_OTR_EXECUTE)    j |= TM_OEXEC;
  518.  
  519.     tmp[headersize] = 0x50;
  520.     Store16(tmp+headersize+1, j);
  521.     headersize += 5;
  522.   }
  523.  
  524.   /* store ID's */
  525.   if(fi->xfi_OwnerUID || fi->xfi_OwnerGID)
  526.   {
  527.     Store16(tmp + headersize-2, 7); /* set header size */
  528.     tmp[headersize] = 0x51;
  529.     Store16(tmp + headersize+1, fi->xfi_OwnerGID);
  530.     Store16(tmp + headersize+3, fi->xfi_OwnerUID);
  531.     headersize += 7;
  532.   }
  533.  
  534.   /* store group name */
  535.   if(fi->xfi_GroupName)
  536.   {
  537.     i = strlen(fi->xfi_GroupName);
  538.     Store16(tmp + headersize-2, i+3); /* set header size */
  539.     tmp[headersize] = 0x52;
  540.     CopyMem(fi->xfi_GroupName, tmp+headersize+1, i);
  541.     headersize += i+3;
  542.   }
  543.  
  544.   /* store user name */
  545.   if(fi->xfi_UserName)
  546.   {
  547.     i = strlen(fi->xfi_UserName);
  548.     Store16(tmp + headersize-2, i+3); /* set header size */
  549.     tmp[headersize] = 0x53;
  550.     CopyMem(fi->xfi_UserName, tmp+headersize+1, i);
  551.     headersize += i+3;
  552.   }
  553.  
  554.   if(!(fi->xfi_Flags & XADFIF_NODATE))
  555.   {
  556.     /* store UNIX time stamp */
  557.     Store16(tmp + headersize-2, 7); /* set header size */
  558.     xadConvertDates(XAD_DATEXADDATE, &fi->xfi_Date, XAD_GETDATEUNIX, &k, TAG_DONE);
  559.     tmp[headersize] = 0x54;
  560.     Store32(tmp+headersize+1, k);
  561.     headersize += 7;
  562.   }
  563.  
  564.   /* store comment */
  565.   if(fi->xfi_Comment)
  566.   {
  567.     i = strlen(fi->xfi_Comment);
  568.     Store16(tmp + headersize-2, i+3); /* set header size */
  569.     tmp[headersize] = 0x71;
  570.     CopyMem(fi->xfi_Comment, tmp+headersize+1, i);
  571.     headersize += i+3;
  572.   }
  573.  
  574.   /* save the stuff */
  575.   Store16(tmp + headersize-2, 5);
  576.   tmp[headersize] = 0x00;
  577.   Store16(tmp + headersize+1, 0); /* clear CRC */
  578.   headersize += 5;
  579.   Store16(tmp + headersize-2, 0); /* clear last header size */
  580.   Store16(tmp, headersize);
  581.   Store16(tmp + headersize-4, xadCalcCRC16(XADCRC16_ID1, 0, headersize, tmp)); /* store CRC */
  582.   Write(fh, tmp, headersize);
  583.   if(size)
  584.     Write(fh, mem, size);
  585. }
  586.  
  587. /************************************************************************/
  588.  
  589. #define MAXMATCH            256    /* formerly F (not more than UCHAR_MAX + 1) */
  590. #define DICSIZ                (1 << 15)
  591. #define TXTSIZ                (DICSIZ * 2 + MAXMATCH)
  592. #define HSHSIZ                (1 << 15)
  593. #define THRESHOLD            3    /* choose optimal value */
  594. #define LIMIT                0x100
  595. #define UCHAR_MAX            ((1<<(sizeof(UBYTE)*8))-1)
  596. #define USHRT_MAX            ((1<<(sizeof(UWORD)*8))-1)
  597. #define NC                 (UCHAR_MAX + MAXMATCH + 2 - THRESHOLD)
  598. #define    MAX_DICBIT            15
  599. #define NP                (MAX_DICBIT + 1)
  600. #define CHAR_BIT              8
  601. #define NT                (USHRT_BIT + 3)
  602. #define USHRT_BIT            16    /* (CHAR_BIT * sizeof(ushort)) */
  603. #define NPT                0x80
  604. #define CBIT                9    /* $\lfloor \log_2 NC \rfloor + 1$ */
  605. #define TBIT                 5    /* smallest integer such that (1 << TBIT) > * NT */
  606.  
  607.   STRPTR  lh5_inmem;
  608.   STRPTR  lh5_outmem;
  609.   ULONG   origsize;
  610.   ULONG   inpos;
  611.   ULONG   compsize;
  612.   ULONG   dicsiz;
  613.   ULONG   txtsiz;
  614.   UWORD   dicbit;
  615.   UWORD   maxmatch;
  616.   UWORD * hash;
  617.   UWORD * prev;
  618.   STRPTR  text;
  619.   STRPTR  too_flag;
  620.   STRPTR  buf;
  621.   UWORD   bufsiz;
  622.   LONG    unpackable;
  623.   ULONG   count;
  624.   ULONG   loc;
  625.   ULONG   encoded_origsize;
  626.   LONG    matchlen;
  627.   ULONG   pos;
  628.   ULONG   remainder;
  629.   ULONG   hval;
  630.   ULONG   matchpos;
  631.   UWORD   cpos;
  632.   UWORD   left[2 * NC - 1];
  633.   UWORD   right[2 * NC - 1];
  634.   UWORD   c_freq[2 * NC - 1];
  635.   UWORD   p_freq[2 * NP - 1];
  636.   UWORD   t_freq[2 * NT - 1];
  637.   UWORD   pt_code[NPT];
  638.   UWORD   c_code[NC];
  639.   UWORD   output_pos;
  640.   UWORD      output_mask;
  641.   UBYTE   pt_len[NPT];
  642.   UBYTE   c_len[NC];
  643.   LONG      pbit;
  644.   LONG      np;
  645.   UBYTE   depth;
  646.   UWORD   len_cnt[17];
  647.   WORD      n;
  648.   UWORD * sort;
  649.   WORD    heapsize;
  650.   WORD    heap[NC + 1];
  651.   UWORD * freq;
  652.   STRPTR  len;
  653.   UBYTE   subbitbuf;
  654.   UBYTE   bitcount;
  655.  
  656. /************************************************************************/
  657.  
  658. static ULONG getbytes(APTR mem, ULONG size)
  659. {
  660.   if(inpos+size > origsize)
  661.     size = origsize-inpos;
  662.   if(size)
  663.   {
  664.     CopyMem(lh5_inmem + inpos, mem, size);
  665.     inpos += size;
  666.   }
  667.   return size;
  668. }
  669.  
  670. static void putcode(UBYTE n, UWORD x)        /* Write rightmost n bits of x */
  671. {
  672.   while(n >= bitcount)
  673.   {
  674.     n -= bitcount;
  675.     subbitbuf += x >> (USHRT_BIT - bitcount);
  676.     x <<= bitcount;
  677.     if(compsize < origsize)
  678.       lh5_outmem[compsize++] = subbitbuf;
  679.     else
  680.       unpackable = 1;
  681.     subbitbuf = 0;
  682.     bitcount = CHAR_BIT;
  683.   }
  684.   subbitbuf += x >> (USHRT_BIT - bitcount);
  685.   bitcount -= n;
  686. }
  687.  
  688. static void putbits(UBYTE n, UWORD x)        /* Write rightmost n bits of x */
  689. {
  690.   x <<= USHRT_BIT - n;
  691.   while(n >= bitcount)
  692.   {
  693.     n -= bitcount;
  694.     subbitbuf += x >> (USHRT_BIT - bitcount);
  695.     x <<= bitcount;
  696.     if(compsize < origsize)
  697.       lh5_outmem[compsize++] = subbitbuf;
  698.     else
  699.       unpackable = 1;
  700.     subbitbuf = 0;
  701.     bitcount = CHAR_BIT;
  702.   }
  703.   subbitbuf += x >> (USHRT_BIT - bitcount);
  704.   bitcount -= n;
  705. }
  706.  
  707. static void init_putbits(void)
  708. {
  709.   bitcount = CHAR_BIT;
  710.   subbitbuf = 0;
  711. }
  712.  
  713. static void make_code(LONG n, UBYTE len[], UWORD code[])
  714. {
  715.   UWORD weight[17];    /* 0x10000ul >> bitlen */
  716.   UWORD start[17];    /* start code */
  717.   UWORD j, k;
  718.   LONG i;
  719.  
  720.   j = 0;
  721.   k = 1 << (16 - 1);
  722.   for(i = 1; i <= 16; i++)
  723.   {
  724.     start[i] = j;
  725.     j += (weight[i] = k) * len_cnt[i];
  726.     k >>= 1;
  727.   }
  728.   for(i = 0; i < n; i++)
  729.   {
  730.     j = len[i];
  731.     code[i] = start[j];
  732.     start[j] += weight[j];
  733.   }
  734. }
  735.  
  736. static void count_len(LONG i)        /* call with i = root */
  737. {
  738.   if(i < n)
  739.     len_cnt[depth < 16 ? depth : 16]++;
  740.   else
  741.   {
  742.     depth++;
  743.     count_len(left[i]);
  744.     count_len(right[i]);
  745.     depth--;
  746.   }
  747. }
  748.  
  749. static void make_len(LONG root)
  750. {
  751.   LONG i, k;
  752.   ULONG cum;
  753.  
  754.   for(i = 0; i <= 16; i++)
  755.     len_cnt[i] = 0;
  756.   count_len(root);
  757.   cum = 0;
  758.   for(i = 16; i > 0; i--)
  759.   {
  760.     cum += len_cnt[i] << (16 - i);
  761.   }
  762.   cum &= 0xffff;
  763.   /* adjust len */
  764.   if(cum)
  765.   {
  766.     len_cnt[16] -= cum;    /* always len_cnt[16] > cum */
  767.     do
  768.     {
  769.       for(i = 15; i > 0; i--)
  770.       {
  771.     if(len_cnt[i])
  772.     {
  773.       len_cnt[i]--;
  774.       len_cnt[i + 1] += 2;
  775.       break;
  776.     }
  777.       }
  778.     } while(--cum);
  779.   }
  780.   /* make len */
  781.   for(i = 16; i > 0; i--)
  782.   {
  783.     k = len_cnt[i];
  784.     while(k > 0)
  785.     {
  786.       len[*sort++] = i;
  787.       k--;
  788.     }
  789.   }
  790. }
  791.  
  792. static void downheap(LONG i) /* priority queue; send i-th entry down heap */
  793. {
  794.   WORD j, k;
  795.  
  796.   k = heap[i];
  797.   while((j = 2 * i) <= heapsize)
  798.   {
  799.     if(j < heapsize && freq[heap[j]] > freq[heap[j + 1]])
  800.       j++;
  801.     if(freq[k] <= freq[heap[j]])
  802.       break;
  803.     heap[i] = heap[j];
  804.       i = j;
  805.   }
  806.   heap[i] = k;
  807. }
  808.  
  809. static WORD make_tree(LONG nparm, UWORD freqparm[], UBYTE lenparm[], UWORD codeparm[]) /* make tree, calculate len[], return root */
  810. {
  811.   WORD i, j, k, avail;
  812.  
  813.   n = nparm;
  814.   freq = freqparm;
  815.   len = lenparm;
  816.   avail = n;
  817.   heapsize = 0;
  818.   heap[1] = 0;
  819.   for(i = 0; i < n; i++)
  820.   {
  821.     len[i] = 0;
  822.     if(freq[i])
  823.       heap[++heapsize] = i;
  824.   }
  825.   if(heapsize < 2)
  826.   {
  827.     codeparm[heap[1]] = 0;
  828.     return heap[1];
  829.   }
  830.   for(i = heapsize / 2; i >= 1; i--)
  831.     downheap(i);    /* make priority queue */
  832.   sort = codeparm;
  833.   do
  834.   {            /* while queue has at least two entries */
  835.     i = heap[1];    /* take out least-freq entry */
  836.     if(i < n)
  837.       *sort++ = i;
  838.     heap[1] = heap[heapsize--];
  839.     downheap(1);
  840.     j = heap[1];    /* next least-freq entry */
  841.     if(j < n)
  842.       *sort++ = j;
  843.     k = avail++;    /* generate new node */
  844.     freq[k] = freq[i] + freq[j];
  845.     heap[1] = k;
  846.     downheap(1);    /* put into queue */
  847.     left[k] = i;
  848.     right[k] = j;
  849.   } while (heapsize > 1);
  850.   sort = codeparm;
  851.   make_len(k);
  852.   make_code(nparm, lenparm, codeparm);
  853.   return k;        /* return root */
  854. }
  855.  
  856. static void encode_c(WORD c)
  857. {
  858.   putcode(c_len[c], c_code[c]);
  859. }
  860.  
  861. static void encode_p(UWORD p)
  862. {
  863.   UWORD c, q;
  864.  
  865.   c = 0;
  866.   q = p;
  867.   while(q)
  868.   {
  869.     q >>= 1;
  870.     c++;
  871.   }
  872.   putcode(pt_len[c], pt_code[c]);
  873.   if(c > 1)
  874.     putbits(c - 1, p);
  875. }
  876.  
  877. static void count_t_freq(void)
  878. {
  879.   WORD i, k, n, count;
  880.  
  881.   for(i = 0; i < NT; i++)
  882.     t_freq[i] = 0;
  883.   n = NC;
  884.   while(n > 0 && c_len[n - 1] == 0)
  885.     n--;
  886.   i = 0;
  887.   while(i < n)
  888.   {
  889.     k = c_len[i++];
  890.     if(k == 0)
  891.     {
  892.       count = 1;
  893.       while(i < n && c_len[i] == 0)
  894.       {
  895.         i++;
  896.         count++;
  897.       }
  898.       if(count <= 2)
  899.         t_freq[0] += count;
  900.       else if(count <= 18)
  901.         t_freq[1]++;
  902.       else if(count == 19)
  903.       {
  904.         t_freq[0]++;
  905.         t_freq[1]++;
  906.       }
  907.       else
  908.         t_freq[2]++;
  909.     }
  910.     else
  911.       t_freq[k + 2]++;
  912.   }
  913. }
  914.  
  915. static void write_pt_len(WORD n, WORD nbit, WORD i_special)
  916. {
  917.   WORD i, k;
  918.  
  919.   while(n > 0 && pt_len[n - 1] == 0)
  920.     n--;
  921.   putbits(nbit, n);
  922.   i = 0;
  923.   while(i < n)
  924.   {
  925.     k = pt_len[i++];
  926.     if(k <= 6)
  927.       putbits(3, k);
  928.     else
  929.       putbits(k - 3, (UWORD) (USHRT_MAX << 1));
  930.     if(i == i_special)
  931.     {
  932.       while(i < 6 && pt_len[i] == 0)
  933.     i++;
  934.       putbits(2, i - 3);
  935.     }
  936.   }
  937. }
  938.  
  939. static void write_c_len(void)
  940. {
  941.   WORD i, k, n, count;
  942.  
  943.   n = NC;
  944.   while(n > 0 && c_len[n - 1] == 0)
  945.     n--;
  946.   putbits(CBIT, n);
  947.   i = 0;
  948.   while(i < n)
  949.   {
  950.     k = c_len[i++];
  951.     if(k == 0)
  952.     {
  953.       count = 1;
  954.       while(i < n && c_len[i] == 0)
  955.       {
  956.         i++;
  957.     count++;
  958.       }
  959.       if(count <= 2)
  960.       {
  961.     for(k = 0; k < count; k++)
  962.       putcode(pt_len[0], pt_code[0]);
  963.       }
  964.       else if(count <= 18)
  965.       {
  966.     putcode(pt_len[1], pt_code[1]);
  967.     putbits(4, count - 3);
  968.       }
  969.       else if(count == 19)
  970.       {
  971.     putcode(pt_len[0], pt_code[0]);
  972.     putcode(pt_len[1], pt_code[1]);
  973.     putbits(4, 15);
  974.       }
  975.       else
  976.       {
  977.     putcode(pt_len[2], pt_code[2]);
  978.     putbits(CBIT, count - 20);
  979.       }
  980.     }
  981.     else
  982.       putcode(pt_len[k + 2], pt_code[k + 2]);
  983.   }
  984. }
  985.  
  986. static void send_block(void)
  987. {
  988.   UBYTE flags = 0;
  989.   UWORD i, k, root, pos, size;
  990.  
  991.   root = make_tree(NC, c_freq, c_len, c_code);
  992.   size = c_freq[root];
  993.   putbits(16, size);
  994.   if(root >= NC)
  995.   {
  996.     count_t_freq();
  997.     root = make_tree(NT, t_freq, pt_len, pt_code);
  998.     if(root >= NT)
  999.     {
  1000.       write_pt_len(NT, TBIT, 3);
  1001.     }
  1002.     else
  1003.     {
  1004.       putbits(TBIT, 0);
  1005.       putbits(TBIT, root);
  1006.     }
  1007.     write_c_len();
  1008.   }
  1009.   else
  1010.   {
  1011.     putbits(TBIT, 0);
  1012.     putbits(TBIT, 0);
  1013.     putbits(CBIT, 0);
  1014.     putbits(CBIT, root);
  1015.   }
  1016.   root = make_tree(np, p_freq, pt_len, pt_code);
  1017.   if(root >= np)
  1018.   {
  1019.     write_pt_len(np, pbit, -1);
  1020.   }
  1021.   else
  1022.   {
  1023.     putbits(pbit, 0);
  1024.     putbits(pbit, root);
  1025.   }
  1026.   pos = 0;
  1027.   for(i = 0; i < size; i++)
  1028.   {
  1029.     if(i % CHAR_BIT == 0)
  1030.       flags = buf[pos++];
  1031.     else
  1032.       flags <<= 1;
  1033.     if(flags & (1 << (CHAR_BIT - 1)))
  1034.     {
  1035.       encode_c(buf[pos++] + (1 << CHAR_BIT));
  1036.       k = buf[pos++] << CHAR_BIT;
  1037.       k += buf[pos++];
  1038.       encode_p(k);
  1039.     }
  1040.     else
  1041.       encode_c(buf[pos++]);
  1042.     if(unpackable)
  1043.       return;
  1044.   }
  1045.   for(i = 0; i < NC; i++)
  1046.     c_freq[i] = 0;
  1047.   for(i = 0; i < np; i++)
  1048.     p_freq[i] = 0;
  1049. }
  1050.  
  1051. void output_st1(UWORD c, UWORD p)
  1052. {
  1053.   output_mask >>= 1;
  1054.   if(output_mask == 0)
  1055.   {
  1056.     output_mask = 1 << (CHAR_BIT - 1);
  1057.     if(output_pos >= bufsiz - 3 * CHAR_BIT)
  1058.     {
  1059.       send_block();
  1060.       if(unpackable)
  1061.         return;
  1062.       output_pos = 0;
  1063.     }
  1064.     cpos = output_pos++;
  1065.     buf[cpos] = 0;
  1066.   }
  1067.   buf[output_pos++] = (unsigned char) c;
  1068.   c_freq[c]++;
  1069.   if(c >= (1 << CHAR_BIT))
  1070.   {
  1071.     buf[cpos] |= output_mask;
  1072.     buf[output_pos++] = (unsigned char) (p >> CHAR_BIT);
  1073.     buf[output_pos++] = (unsigned char) p;
  1074.     c = 0;
  1075.     while(p)
  1076.     {
  1077.       p >>= 1;
  1078.       c++;
  1079.     }
  1080.     p_freq[c]++;
  1081.   }
  1082. }
  1083.  
  1084. static void init_slide(void)
  1085. {
  1086.   ULONG i;
  1087.  
  1088.   for(i = 0; i < HSHSIZ; i++)
  1089.   {
  1090.     hash[i] = 0;
  1091.     too_flag[i] = 0;
  1092.   }
  1093. }
  1094.  
  1095. static void insert(void)
  1096. {
  1097.   prev[pos & (dicsiz - 1)] = hash[hval];
  1098.   hash[hval] = pos;
  1099. }
  1100.  
  1101. static void update(void)
  1102. {
  1103.   ULONG i, j;
  1104.   LONG n, m;
  1105.  
  1106.   i = 0;
  1107.   j = dicsiz;
  1108.   m = txtsiz-dicsiz;
  1109.   while(m-- > 0)
  1110.     text[i++] = text[j++];
  1111.  
  1112.   n = getbytes(&text[txtsiz - dicsiz], (ULONG) dicsiz);
  1113.  
  1114.   remainder += n;
  1115.   encoded_origsize += n;
  1116.  
  1117.   pos -= dicsiz;
  1118.   for(i = 0; i < HSHSIZ; i++)
  1119.   {
  1120.     j = hash[i];
  1121.     hash[i] = (j > dicsiz) ? j - dicsiz : 0;
  1122.     too_flag[i] = 0;
  1123.   }
  1124.   for(i = 0; i < dicsiz; i++)
  1125.   {
  1126.     j = prev[i];
  1127.     prev[i] = (j > dicsiz) ? j - dicsiz : 0;
  1128.   }
  1129. }
  1130.  
  1131. static void get_next(void)
  1132. {
  1133.   remainder--;
  1134.   if(++pos >= txtsiz - maxmatch)
  1135.   {
  1136.     update();
  1137.   }
  1138.   hval = ((hval << 5) ^ text[pos + 2]) & (ULONG)(HSHSIZ - 1);
  1139. }
  1140.  
  1141. static void match_insert(void)
  1142. {
  1143.   ULONG scan_pos, scan_end, len;
  1144.   STRPTR a, b;
  1145.   ULONG chain, off, h, max;
  1146.  
  1147.   max = maxmatch; /* MAXMATCH; */
  1148.   if(matchlen < THRESHOLD - 1)
  1149.     matchlen = THRESHOLD - 1;
  1150.   matchpos = pos;
  1151.  
  1152.   off = 0;
  1153.   for(h = hval; too_flag[h] && off < maxmatch - THRESHOLD;)
  1154.   {
  1155.     h = ((h << 5) ^ text[pos + (++off) + 2]) & (ULONG)(HSHSIZ - 1);
  1156.   }
  1157.   if(off == maxmatch - THRESHOLD)
  1158.     off = 0;
  1159.   for(;;)
  1160.   {
  1161.     chain = 0;
  1162.     scan_pos = hash[h];
  1163.     scan_end = (pos > dicsiz) ? pos + off - dicsiz : off;
  1164.     while(scan_pos > scan_end)
  1165.     {
  1166.       chain++;
  1167.       if(text[scan_pos + matchlen - off] == text[pos + matchlen])
  1168.       {
  1169.         a = text + scan_pos - off;
  1170.         b = text + pos;
  1171.         for(len = 0; len < max && *a++ == *b++; len++)
  1172.           ;
  1173.         if(len > matchlen)
  1174.         {
  1175.       matchpos = scan_pos - off;
  1176.       if((matchlen = len) == max)
  1177.       {
  1178.         break;
  1179.           }
  1180.     }
  1181.       }
  1182.       scan_pos = prev[scan_pos & (dicsiz - 1)];
  1183.     }
  1184.     if(chain >= LIMIT)
  1185.       too_flag[h] = 1;
  1186.  
  1187.     if(matchlen > off + 2 || off == 0)
  1188.       break;
  1189.     max = off + 2;
  1190.     off = 0;
  1191.     h = hval;
  1192.   }
  1193.   prev[pos & (dicsiz - 1)] = hash[hval];
  1194.   hash[hval] = pos;
  1195. }
  1196.  
  1197. static void encode_start_st1(void)
  1198. {
  1199.   LONG i;
  1200.  
  1201.   if(dicbit <= (MAX_DICBIT - 2))
  1202.   {
  1203.      pbit = 4;    /* lh4,5 etc. */
  1204.      np = 14;
  1205.   }
  1206.   else
  1207.   {
  1208.     pbit = 5;    /* lh6 */
  1209.     np = 16;
  1210.   }
  1211.  
  1212.   for(i = 0; i < NC; i++)
  1213.     c_freq[i] = 0;
  1214.   for(i = 0; i < np; i++)
  1215.     p_freq[i] = 0;
  1216.   output_pos = output_mask = 0;
  1217.   init_putbits();
  1218.   buf[0] = 0;
  1219. }
  1220.  
  1221. static void encode_end_st1(void)
  1222. {
  1223.   if(!unpackable)
  1224.   {
  1225.     send_block();
  1226.     putbits(CHAR_BIT - 1, 0);    /* flush remaining bits */
  1227.   }
  1228. }
  1229.  
  1230. static void encode(void)
  1231. {
  1232.   LONG lastmatchlen, i;
  1233.   ULONG lastmatchoffset;
  1234.  
  1235.   compsize = count = 0;
  1236.   unpackable = 0;
  1237.  
  1238.   init_slide();  
  1239.  
  1240.   encode_start_st1();
  1241.  
  1242.   for(i = 0; i < TXTSIZ; ++i)
  1243.     text[i] = ' ';
  1244.  
  1245.   remainder = getbytes(&text[dicsiz], txtsiz-dicsiz);
  1246.   encoded_origsize = remainder;
  1247.   matchlen = THRESHOLD - 1;
  1248.   pos = dicsiz;
  1249.  
  1250.   if(matchlen > remainder)
  1251.     matchlen = remainder;
  1252.   hval = ((((text[dicsiz] << 5) ^ text[dicsiz + 1]) << 5) ^ text[dicsiz + 2]) & (ULONG)(HSHSIZ - 1);
  1253.  
  1254.   insert();
  1255.   while(remainder > 0 && !unpackable)
  1256.   {
  1257.     lastmatchlen = matchlen;  lastmatchoffset = pos - matchpos - 1;
  1258.     --matchlen;
  1259.     get_next();
  1260.     match_insert();
  1261.     if(matchlen > remainder)
  1262.       matchlen = remainder;
  1263.     if(matchlen > lastmatchlen || lastmatchlen < THRESHOLD)
  1264.     {
  1265.       output_st1(text[pos - 1], 0);
  1266.       count++;
  1267.     }
  1268.     else
  1269.     {
  1270.       output_st1(lastmatchlen + (UCHAR_MAX + 1 - THRESHOLD), (lastmatchoffset) & (dicsiz-1) );
  1271.       --lastmatchlen;
  1272.  
  1273.       while(--lastmatchlen > 0)
  1274.       {
  1275.         get_next();
  1276.         insert();
  1277.         count++;
  1278.       }
  1279.       get_next();
  1280.       matchlen = THRESHOLD - 1;
  1281.       match_insert();
  1282.       if(matchlen > remainder)
  1283.         matchlen = remainder;
  1284.     }
  1285.   }
  1286.   encode_end_st1();
  1287. }
  1288.  
  1289. static STRPTR alloc_buf(void)
  1290. {
  1291.   bufsiz = 16 * 1024 * 2;    /* 65408U; */
  1292.   while(!(buf = (STRPTR) AllocMem(bufsiz, MEMF_ANY)))
  1293.   {
  1294.     bufsiz = (bufsiz / 10) * 9;
  1295.     if(bufsiz < 4 * 1024)
  1296.       break;
  1297.   }
  1298.   return buf;
  1299. }
  1300.  
  1301. ULONG MakeLH(STRPTR mem, ULONG size, ULONG bits)
  1302. {
  1303.   ULONG ok = 0;
  1304.   STRPTR mem2;
  1305.   
  1306.   if((mem2 = (STRPTR) AllocVec(size, MEMF_CLEAR)))
  1307.   {
  1308.     lh5_inmem = mem;
  1309.     lh5_outmem = mem2;
  1310.     origsize = size;
  1311.     compsize = 0;
  1312.     depth = 0;
  1313.     inpos = 0;
  1314.  
  1315.     maxmatch = MAXMATCH;
  1316.     dicbit = bits;
  1317.     dicsiz = (1 << dicbit);
  1318.     txtsiz = dicsiz*2+maxmatch;
  1319.  
  1320.     if(alloc_buf())
  1321.     {
  1322.       if((hash = (UWORD *) AllocVec(HSHSIZ * 2, MEMF_CLEAR)))
  1323.       {
  1324.     if((prev = (UWORD *) AllocVec(DICSIZ * 2, MEMF_CLEAR)))
  1325.     {
  1326.       if((text = (STRPTR) AllocVec(TXTSIZ, MEMF_CLEAR)))
  1327.       {
  1328.         if((too_flag = (STRPTR) AllocVec(HSHSIZ, MEMF_CLEAR)))
  1329.         {
  1330.           encode();
  1331.           if(compsize < size && !unpackable)
  1332.           {
  1333.             CopyMem(mem2, mem, compsize);
  1334.             size = compsize;
  1335.             ok = 1;
  1336.           }
  1337.           FreeVec(too_flag);
  1338.         }
  1339.         FreeVec(text);
  1340.       }
  1341.       FreeVec(prev);
  1342.     }
  1343.     FreeVec(hash);
  1344.       }
  1345.       FreeMem(buf, bufsiz);
  1346.     }
  1347.     FreeVec(mem2);
  1348.   }
  1349.  
  1350.   return ok ? size : 0;
  1351. }
  1352.  
  1353.